#pragma once
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <GL/glut.h>
#include <dirent.h>
#include "../gl/Drawabe.h"
#include "../gl/Application.h"
#include "view.h"
#include "model.h"

GraphicsOptions graphicsOptions = {
        .cell={.size=32},
        .grid={
                .line_width=1,
                .color = Color(64, 64, 0, 127),
        },
        .border={
                .width = 32,
                .color = Color(127, 0, 127),
        },
        .color={
                .bg = Color(0, 0, 0),
                .snake = Color(127, 127, 127),
                .fail_snake = Color(127, 0, 0),
                .pause_snake = Color(127, 127, 127),
        }
};
GameOptions gameOptions = {
        .x_sz = 20,
        .y_sz = 20,
        .food_move_percent = 30,
        .init_len = 4,
        .foods_count = 10,
        .controller = {
                .snake_timer = 300,
                .food_timer = 100,
                .food_move_percent = 30
        }
};

enum Timers{
    TIMER_FOOD_MOVE,
    TIMER_SNAKE_MOVE
};

class PythonApplication: public GlApplication {
private:
    View * view = nullptr;
    Game * game = nullptr;
public:

    PythonApplication(int argc, char **argv) : GlApplication(argc, argv, true) {
        this->game = new Game(gameOptions);
        this->view = new View(graphicsOptions, this->game);
        this->game->reset();
    }

    ~PythonApplication() {
        delete this->game;
        delete this->view;
    }

    void draw() override {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        view->draw();
        glutSwapBuffers();
    }

    void on_timer(int id) override {
        if (this->game!= nullptr) {
            switch (id) {
                case Timers::TIMER_FOOD_MOVE: {
                    this->game->move_foods();
                    this->init_timer(Timers::TIMER_FOOD_MOVE, gameOptions.controller.food_timer);
                    break;
                }
                case Timers::TIMER_SNAKE_MOVE: {
                    this->game->move_snake();
                    this->init_timer(Timers::TIMER_SNAKE_MOVE, gameOptions.controller.snake_timer);
                    break;
                }
                default:
                    break;
            }
            glutPostRedisplay();
            //this->draw();
        }
    }

    void on_key_down(int key, bool spec, int x, int y) override {
        printf("key: %d, x: %d, y: %d\n", key, x, y);
        if (spec) {
            if ((game->state==GameState::GS_PAUSE) || (game->state==GameState::GS_RUN)) {
                game->state = GameState::GS_RUN;
                switch (key) {
                    case 100://LEFT
                        game->move = MoveAction::MV_LEFT;
                        break;
                    case 101://UP
                        game->move = MoveAction::MV_UP;
                        break;
                    case 102://RIGHT
                        game->move = MoveAction::MV_RIGHT;
                        break;
                    case 103://DOWN
                        game->move = MoveAction::MV_DOWN;
                        break;
                }
            }
        } else {
            switch (key) {
                case 27: //esc
                    delete this;
                    exit(0);
                case 32: //space
                    switch (game->state) {
                        case GS_RUN:
                            game->state = GS_PAUSE;
                            break;
                        case GS_PAUSE:
                            game->state = GS_RUN;
                            break;
                        case GS_DONE:
                            game->reset();
                            break;
                    }
                    break;
            }
        }
    }
protected:
    void pre_loop() override {
        this->init_timer(Timers::TIMER_FOOD_MOVE, gameOptions.controller.food_timer);
        this->init_timer(Timers::TIMER_SNAKE_MOVE, gameOptions.controller.snake_timer);
    }

    void create_scene() override{
        glClear(GL_COLOR_BUFFER_BIT);
        glEnable(GL_TEXTURE_2D);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    GlWindow * createWindow() override {
        auto * window = new GlWindow(200, 200, 800, 800, "Python");
        return window;
    }

    void createResources() override {
        this->view->prepare();
    }

};
